﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using System.Windows.Forms;
using Krs.Ats.IBNet;
using Krs.Ats.IBNet.Contracts;

using Forex.IB.RealTimeBars.WinApp.Extensions;
using Forex.IB.RealTimeBars.Components;
using System.Diagnostics;
using System.IO;



namespace Forex.IB.RealTimeBars.WinApp
{
    public class HistoricaData
    {
        private ConnectionParametersVO connParam = new ConnectionParametersVO();
        delegate void SetTextCallback(string text);
        private static Contract IdealPro;
        IBClient client = new IBClient();
        static RealTimeData mainClass = RealTimeData.MainFormForLogging;
        static SetTextCallback logAddDelegate; 

        public HistoricaData(ConnectionParametersVO conn)
        {
            connParam.ClientId = conn.ClientId + 1;
            connParam.PortNumber = conn.PortNumber;
        }

        public void GetHistoricalData()
        {
            try
            {
                client.ThrowExceptions = true;
                client.HistoricalData += client_HistoricalData;
                MaintenanceRoutine();
                DateTime dateTime = DateTime.Now;
                SqlHelper helper = new SqlHelper();
                DataTable dt = new DataTable();
                //Update the process
                helper.UpdateProcess(false);
                //Get tickers
                dt = helper.GetTickers();

                //Begin Log
                helper.AddMessage("Historical Data Connecting to Interactive Brokers....");
                updateLog("Historical Data Connecting to Interactive Brokers....");
                //End Log
                try
                {
                    client.Connect("127.0.0.1", connParam.PortNumber, connParam.ClientId);
                    client.RequestCurrentTime();
                }
                catch (Exception ex)
                {
                    throw new Exception("Please check if the interactive broker TWS client is running");
                }

                if (client.Connected)
                {
                    //Begin Log
                    helper.AddMessage("Historical Data connected to Interactive Brokers");
                    updateLog("Historical Data connected to Interactive Brokers");
                    //End Log
                    // Thread.Sleep(30000);
                    System.Threading.Tasks.Parallel.ForEach(dt.AsEnumerable(), row =>
                    {
                        string[] forexTickers = row["Ticker"].ToString().Split('/');
                        Krs.Ats.IBNet.Contracts.Forex frx = new Krs.Ats.IBNet.Contracts.Forex(forexTickers[0], forexTickers[1]);
                        IdealPro = new Contract(forexTickers[0], "IDEALPRO", SecurityType.Cash, forexTickers[1]);
                        client.RequestHistoricalData(int.Parse(row["Ticker_Id"].ToString()), IdealPro, dateTime, "4 D", BarSize.OneMinute, HistoricalDataType.Midpoint, 1);
                    });

                    //Begin Log
                    helper.AddMessage("Historical data request has been completed.");
                    updateLog("Historical data request has been completed.");
                    //End Log
                }
                else
                {
                    helper.AddMessage("Client is disconnected.");
                    updateLog("Client is disconnected.");
                }

                int count = 0;
                DateTime historicalLoadTime = dateTime.AddSeconds(-dateTime.Second);
                while (!helper.IsHistoricalDataLoaded(historicalLoadTime))
                {
                    helper.AddMessage("Check Date Time:" + historicalLoadTime.ToString());
                    updateLog("Loading data.....");
                    if (count < 10)
                    {
                        Thread.Sleep(120000);
                        count = count + 1;
                    }
                    else
                    {
                        helper.AddMessage("Historical data request load passed the wait time.....");
                        updateLog("Historical data request load passed the wait time.....");
                        break;
                    }
                }

                if (helper.IsHistoricalDataLoaded(dateTime.AddSeconds(-dateTime.Second)))
                {
                    helper.AddMessage("Historical data request has been loaded successfully.");
                    updateLog("Historical data request has been loaded successfully.");

                    DataTable dtTickersIntervals = new DataTable();
                    dtTickersIntervals.Columns.Add("TickerID", typeof(int));
                    dtTickersIntervals.Columns.Add("Interval", typeof(int));
                    dtTickersIntervals.Columns.Add("Ticker", typeof(string));

                    int[] intervals = new int[3];
                    intervals[0] = 15;
                    intervals[1] = 30;
                    intervals[2] = 60;

                    var stopwatch = Stopwatch.StartNew();

                    for (int i = 0; i < intervals.Length; i++)
                    {
                        foreach (DataRow row in dt.Rows)
                        {
                            DataRow dtRow = dtTickersIntervals.NewRow();
                            dtRow["TickerID"] = row["Ticker_Id"];
                            dtRow["Interval"] = intervals[i];
                            dtRow["Ticker"] = row["Ticker"];
                            dtTickersIntervals.Rows.Add(dtRow);
                            int tickerID = int.Parse(row["Ticker_Id"].ToString());
                        }
                    }

                    int rowcounts = dtTickersIntervals.Rows.Count;
                    Thread[] oThread = new Thread[rowcounts];
                    foreach (DataRow row in dtTickersIntervals.Rows)
                    {
                        helper.AddMessage("Making Ichimoku....., Ticker id:" + row["TickerID"].ToString() + "...Interval:" + row["Interval"].ToString());
                        updateLog("Making Ichimoku....., Ticker:" + row["Ticker"].ToString() + "...Interval:" + row["Interval"].ToString());
                        LoadHistoricalData loadData = new LoadHistoricalData(int.Parse(row["TickerID"].ToString()), int.Parse(row["Interval"].ToString()), row["Ticker"].ToString());
                        rowcounts = rowcounts - 1;
                        oThread[rowcounts] = new Thread(new ThreadStart(loadData.LoadData));
                    }

                    for (int i = 0; i < oThread.Length; i++)
                    {
                        oThread[i].IsBackground = true;
                        oThread[i].Start();
                    }

                    for (int i = 0; i < oThread.Length; i++)
                    {
                        oThread[i].Join();
                    }

                    helper.AddMessage("Making Ichimoku Historical data completed successfully. Elapsed Time take in" + stopwatch.ElapsedMilliseconds.ToString());
                    updateLog("Making Ichimoku Historical data completed successfully. Elapsed Time take in" + stopwatch.ElapsedMilliseconds.ToString());
                    helper.MakeIchimokuIndicatorsFrmHistoricalDataCriteria();
                    helper.AddMessage("Criteria Ichimoku Historical data ran successfully.");
                    updateLog("Criteria Ichimoku Historical data ran successfully.");
                    //Update the process
                    helper.UpdateProcess(true);
                }

            }
            catch (System.Threading.ThreadAbortException ex)
            {

                // do nothing

            }
            catch (Exception ex)
            {

                SqlHelper helper = new SqlHelper();
                helper.AddMessage("Error: " + ex.Message.ToString());
                updateLog("Error: " + ex.Message.ToString());
                throw ex;
            }
        }

        private void client_HistoricalData(object sender, HistoricalDataEventArgs e)
        {
            SqlHelper helper = new SqlHelper();
            helper.AddIchimokuIndicators(int.Parse(e.RequestId.ToString()), DateTime.Parse(e.Date.ToString()), double.Parse(e.Open.ToString()), double.Parse(e.Close.ToString()), double.Parse(e.High.ToString()), double.Parse(e.Low.ToString()), long.Parse(e.Volume.ToString()));
        }



        private static void MaintenanceRoutine()
        {
            try
            {
                SqlHelper helper = new SqlHelper();
            //    DataTable dt = helper.GetIchimokuIndicatorsToArchive();

            //    if (dt == null)
            //        throw new ApplicationException(string.Format("Error in '{0}': No data was returned from procedure", "Ichimoku Indicators"));

            //    // check if any data
            //    if (dt.Rows.Count == 0)
            //    {
            //        // if there is no data, nothing is under the threshold
            //        throw new ApplicationException(string.Format("Error in '{0}': No data was returned from procedure", "Ichimoku Indicators"));

            //    }

            //    MemoryStream stream = new MemoryStream();
            //    Byte[] content = System.Text.Encoding.UTF8.GetBytes(CSVFileBuilder.ConvertToCsv(dt, true));
            //    stream.Write(content, 0, content.Length);
            //    stream.Seek(0, SeekOrigin.Begin);

            //    if (stream.Length == 0) return;


            //    using (FileStream fileStream = System.IO.File.Create(Common.FlatFile + "IChimokuIndicators_" + DateTime.Now.ToString() + ".log", (int)stream.Length))
            //    {
            //        // Fill the bytes[] array with the stream data 
            //        byte[] bytesInStream = new byte[stream.Length];
            //        stream.Read(bytesInStream, 0, (int)bytesInStream.Length);

            //        // Use FileStream object to write to the specified file 
            //        fileStream.Write(bytesInStream, 0, bytesInStream.Length);
            //    }

                helper.ResetIchimokuIndicators();
            }
            catch (Exception ex)
            {
                updateLog("Error: "+ex.Message.ToString());
            }

        }


      
        private void SaveStreamToFile(string fileFullPath, Stream stream)
        {
            if (stream.Length == 0) return;

            // Create a FileStream object to write a stream to a file 
            using (FileStream fileStream = System.IO.File.Create(fileFullPath, (int)stream.Length))
            {
                // Fill the bytes[] array with the stream data 
                byte[] bytesInStream = new byte[stream.Length];
                stream.Read(bytesInStream, 0, (int)bytesInStream.Length);

                // Use FileStream object to write to the specified file 
                fileStream.Write(bytesInStream, 0, bytesInStream.Length);
            }
        }

        public static void updateLog(string message)
        {
            logAddDelegate = mainClass.SetHistoricalDataStatus;
            logAddDelegate(message);
        }


    }

    public class LoadHistoricalData
    {
        static RealTimeData mainClass = RealTimeData.MainFormForLogging;
        static SetTextCallback logAddDelegate; 
        private int _ticker_Id;
        private int _interval;
        private string _ticker;

        private SqlHelper helper;

        private static string GetConnectionString()
        {
            return Common.ConnectionString;
        }

        public LoadHistoricalData(int TickerID, int Interval,string Ticker)
        {
            _ticker_Id = TickerID;
            _interval = Interval;
            _ticker = Ticker;
        }

        public void LoadData()
        {
            try
            {
                helper = new SqlHelper();
                helper.AddMessage("Making Ichimoku begin for Ticker id:" + _ticker_Id.ToString() + "...Interval:" + _interval.ToString() + "...ThreadId:" + Thread.CurrentThread.ManagedThreadId.ToString());
                updateLog("Making Ichimoku, begin for Ticker :" + _ticker.ToString() + "...Interval:" + _interval.ToString() + "...ThreadId:" + Thread.CurrentThread.ManagedThreadId.ToString());
                RunCommandAsynchronously();
            }
            catch (Exception ex)
            {
                helper = new SqlHelper();
                helper.AddMessage("Error occured for SqlHelper" + " " + ex.Message.ToString() + ". Debug Information: " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            }
        }

        private void RunCommandAsynchronously()
        {

            using (SqlConnection connection = new SqlConnection(GetConnectionString()))
            {
                try
                {
                    SqlCommand command = new SqlCommand("dbo.sp_MakeIchimokuIndicators_Hist", connection);
                    command.Parameters.AddWithValue("@Ticker_Id", _ticker_Id);
                    command.Parameters.AddWithValue("@Interval", _interval);
                    command.CommandTimeout = 3600;
                    command.CommandType = CommandType.StoredProcedure;
                    connection.Open();

                    IAsyncResult result = command.BeginExecuteNonQuery();
                    while (!result.IsCompleted)
                    {
                        System.Threading.Thread.Sleep(60000);
                        helper.AddMessage("Making Ichimoku executing for Ticker id:" + _ticker_Id.ToString() + "...Interval:" + _interval.ToString() + "...ThreadId:" + Thread.CurrentThread.ManagedThreadId.ToString());
                        updateLog("Making Ichimoku, executing for Ticker: " + _ticker.ToString() + "...Interval: " + _interval.ToString() + "...ThreadId: " + Thread.CurrentThread.ManagedThreadId.ToString());
                    }
                    if (connection.State == ConnectionState.Open)
                    {
                        connection.Close();
                        helper.AddMessage("Closing sql connection for Ticker id:" + _ticker_Id.ToString() + "...Interval:" + _interval.ToString() + "...ThreadId:" + Thread.CurrentThread.ManagedThreadId.ToString());
                    }
                }
                catch (SqlException ex)
                {
                    helper = new SqlHelper();
                    helper.AddMessage("Error: " + ex.Message);
                    updateLog("Error: " + ex.Message);
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                    throw ex;

                }
                catch (InvalidOperationException ex)
                {
                    helper = new SqlHelper();
                    helper.AddMessage("Error: " + ex.Message);
                    updateLog("Error: " + ex.Message);
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                    throw ex;

                }
                catch (Exception ex)
                {
                    helper = new SqlHelper();
                    helper.AddMessage("Error: " + ex.Message);
                    updateLog("Error: " + ex.Message);
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                    throw ex;

                }
            }
        }

        private static void updateLog(string message)
        {
            logAddDelegate = mainClass.SetHistoricalDataStatus;
            logAddDelegate(message);
        } 
    }
}

